home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / wics.zip / PRINTER.CPP < prev    next >
C/C++ Source or Header  |  1993-03-05  |  22KB  |  716 lines

  1. /*==========================================================================================*/
  2. /*                                                                                          */
  3. /*    Windows Interface Construction Set                                                      */
  4. /*    Version 1.00                                                                            */
  5. /*                                                                                          */
  6. /*------------------------------------------------------------------------------------------*/
  7. /*    PRINTER.CPP - Windows Printing Classes                                                  */
  8. /*------------------------------------------------------------------------------------------*/
  9. /*                                                                                          */
  10. /*    Copyright ⌐ 1993 by Microdyne Development Technologies                                  */
  11. /*    All rights reserved.                                                                    */
  12. /*                                                                                          */
  13. /*==========================================================================================*/
  14.  
  15. #include <printer.h>
  16. #include <safepool.h>
  17. #include <wics.h>
  18.  
  19. /*------------------------------------------------------------------------------------------*/
  20. /*    Helper functions for the YieldProc procedure.                                            */
  21. /*------------------------------------------------------------------------------------------*/
  22.  
  23. BOOL ProcessDlgMsg(LPMSG PMessage, PTApplication Application)
  24. {
  25.     if (Application->KBHandlerWnd && Application->KBHandlerWnd->HWindow)
  26.         return IsDialogMessage(Application->KBHandlerWnd->HWindow, PMessage);
  27.     else
  28.         return FALSE;
  29. }
  30.  
  31. BOOL ProcessAccels(LPMSG PMessage, PTApplication Application)
  32. {
  33.     return Application->HAccTable &&
  34.         TranslateAccelerator(Application->MainWindow->HWindow, Application->HAccTable, PMessage);
  35. }
  36.  
  37. BOOL ProcessMDIAccels(LPMSG PMessage, PTApplication Application)
  38. {
  39.     return (PTWindowsObject)(Application->MainWindow->GetClient()) &&
  40.             TranslateMDISysAccel(((PTWindowsObject)(Application->MainWindow->GetClient()))->HWindow, PMessage);
  41. }
  42.  
  43. BOOL ProcessAppMsg(LPMSG PMessage)
  44. {
  45.     PTApplication Application = GetApplicationObject();
  46.  
  47.     if ( Application->KBHandlerWnd )
  48.         if ( Application->KBHandlerWnd->IsFlagSet(WB_MDICHILD) )
  49.             return ProcessMDIAccels(PMessage, Application) ||
  50.                    ProcessDlgMsg(PMessage, Application) ||
  51.                    ProcessAccels(PMessage, Application);
  52.         else
  53.             return ProcessDlgMsg(PMessage, Application) ||
  54.                    ProcessMDIAccels(PMessage, Application) ||
  55.                    ProcessAccels(PMessage, Application);
  56.     else
  57.         return ProcessMDIAccels(PMessage, Application) ||
  58.                ProcessAccels(PMessage, Application);
  59. }
  60.  
  61. /*------------------------------------------------------------------------------------------*/
  62. /*    YieldProc                                                                                */
  63. /*------------------------------------------------------------------------------------------*/
  64. /*                                                                                          */
  65. /*    Abstract:                                                                                */
  66. /*                                                                                          */
  67. /*    This procedure is used to allow messages waiting in the message queue to be processed    */
  68. /*    by other windows while the printing process is being done. This allows Windows to        */
  69. /*    multi-task during the (potentially) long printing process.                                */
  70. /*                                                                                          */
  71. /*------------------------------------------------------------------------------------------*/
  72.  
  73. BOOL FAR PASCAL _export YieldProc(BOOL UserAbort)
  74. {
  75.     MSG Msg;
  76.  
  77.     while (!UserAbort && PeekMessage(&Msg, NULL, NULL, NULL, PM_REMOVE))
  78.         if (!ProcessAppMsg(&Msg))
  79.         {
  80.             TranslateMessage(&Msg);
  81.             DispatchMessage(&Msg);
  82.         }
  83.  
  84.     return (!UserAbort);
  85. }
  86.  
  87.  
  88. /*------------------------------------------------------------------------------------------*/
  89. /*    Class TPrintedPage                                                                        */
  90. /*------------------------------------------------------------------------------------------*/
  91. /*                                                                                          */
  92. /*    Abstract:                                                                                */
  93. /*                                                                                          */
  94. /*    TPrintedPage represents the physical printed document which is to be sent to a printer    */
  95. /*    to be printed. TPrintedPage does the rendering of the document onto the printer. For    */
  96. /*    every document, or document type, a corresponding TPrintedPage class should be created. */
  97. /*                                                                                          */
  98. /*------------------------------------------------------------------------------------------*/
  99.  
  100. TPrintedPage::TPrintedPage(Pchar ATitle)
  101. {
  102.     HDC        hdc ;
  103.  
  104.     Title = new char[lstrlen(ATitle)+1];
  105.     lstrcpy (Title, ATitle);
  106.  
  107.     hdc = GetDC (NULL);
  108.     ScreenDpi.x = GetDeviceCaps (hdc, LOGPIXELSX);
  109.     ScreenDpi.y = GetDeviceCaps (hdc, LOGPIXELSY);
  110.     ReleaseDC (NULL, hdc);
  111. }
  112.  
  113. TPrintedPage::~TPrintedPage()
  114. {
  115.     delete Title;
  116. }
  117.  
  118. BOOL TPrintedPage::IsNextPage()
  119. {
  120.     return FALSE;
  121. }
  122.  
  123. /*    This member takes a LOGFONT structure filled with a font created for the screen and
  124.  *    computes the point size of the font. This routine can be used to obtain a point size
  125.  *  of a screen font so that the font can be rendered on the page at the appropriate size.
  126.  */
  127.  
  128. int TPrintedPage::GetPointSize (LOGFONT FAR *lplf)
  129. {
  130.     int        PixelSize;
  131.     int        PointSize;
  132.     int        LogPixelsY;
  133.     int        RoundFactor;
  134.     DWORD    lIntermediate;
  135.     HDC        hdc;
  136.  
  137.     /*    The font size will come in pixel height. We must convert pixel height
  138.      *    to its equivalent point size.                                            
  139.      *
  140.      *    First, if the input parameter is positive, eliminate the internal         
  141.      *    leading value to get the font height.
  142.      */
  143.  
  144.     if ( (int) lplf->lfHeight > 0 )
  145.     {
  146.         HFONT        hCurrentFont ;
  147.         TEXTMETRIC    tm;
  148.  
  149.         hdc = GetDC (NULL);
  150.  
  151.         hCurrentFont = CreateFontIndirect(lplf);
  152.         SelectObject( hdc, hCurrentFont );
  153.  
  154.         GetTextMetrics (hdc, &tm);
  155.  
  156.         PixelSize = lplf->lfHeight - tm.tmInternalLeading ;
  157.  
  158.         ReleaseDC (NULL, hdc);
  159.         DeleteObject (hCurrentFont);
  160.     }
  161.     else
  162.            PixelSize = abs(lplf->lfHeight);
  163.  
  164.     /*    Now that we have the pixel height, calcuate the point size    */
  165.  
  166.     hdc = GetDC (NULL);
  167.     LogPixelsY = GetDeviceCaps (hdc, LOGPIXELSY);
  168.     ReleaseDC (NULL, hdc);
  169.  
  170.     RoundFactor = LogPixelsY / 2 ;
  171.     lIntermediate = 72L * PixelSize + RoundFactor ;
  172.     PointSize = (int) (lIntermediate / LogPixelsY );
  173.  
  174.     return PointSize;
  175. }
  176.  
  177. /*------------------------------------------------------------------------------------------*/
  178. /*    Class TPrinterAbortDlg                                                                    */
  179. /*------------------------------------------------------------------------------------------*/
  180. /*                                                                                          */
  181. /*    Abstract:                                                                               */
  182. /*                                                                                          */
  183. /*    TPrinterAbortDlg represents the "printing" dialog box that is displayed while TPrinter    */
  184. /*    is printing a TPrintedPage.                                                                */
  185. /*                                                                                          */
  186. /*------------------------------------------------------------------------------------------*/
  187.  
  188. static BOOL RegFails(void *AWindowsObject, void *)
  189. {
  190.   return !((PTWindowsObject)AWindowsObject)->Register();
  191. }
  192.  
  193. TPrinterAbortDlg::TPrinterAbortDlg(PTWindowsObject AParent, PTDialogTemplate ADialogTemplate, Pchar Title, LPSTR Device, LPSTR Port, BOOL& fUserAbort)
  194.                 : TIndirectDialog(AParent, ADialogTemplate)
  195. {
  196.     LPCONTROLDATA    lpcd;
  197.     LPSTR            lpText;
  198.     WORD FAR *        lpWord;
  199.  
  200.     pfUserAbort = &fUserAbort;
  201.     ATitle         = Title;
  202.     ADevice     = Device;
  203.     APort         = Port;
  204.  
  205.     MaxPage     = 0;
  206.     CurrentPage = 0;
  207. }
  208.  
  209. TPrinterAbortDlg::~TPrinterAbortDlg()
  210. {
  211. }
  212.  
  213. void TPrinterAbortDlg::SetupWindow()
  214. {
  215.     char    szDevice[80];
  216.  
  217.     TIndirectDialog::SetupWindow();
  218.  
  219.     EnableMenuItem(GetSystemMenu(HWindow, FALSE), SC_CLOSE, MF_GRAYED);
  220.  
  221.     SendDlgItemMsg (ID_TITLE, WM_SETTEXT, 0, (LPARAM) ATitle);
  222.  
  223.     wsprintf (szDevice, "on the %s Printer", ADevice);
  224.     SendDlgItemMsg (ID_DEVICE, WM_SETTEXT, 0, (LPARAM) szDevice);
  225.  
  226.     wsprintf (szDevice, "connected to %s", APort);
  227.     SendDlgItemMsg (ID_PORT, WM_SETTEXT, 0, (LPARAM) szDevice);
  228.  
  229.     SendDlgItemMsg (ID_PAGEOFPAGE, WM_SETTEXT, 0, (LPARAM) "");
  230. }
  231.  
  232. void TPrinterAbortDlg::SetMaxPage (int p)
  233. {
  234.     char    szLine[80];
  235.  
  236.     MaxPage = p;
  237.  
  238.     if ( MaxPage )
  239.     {
  240.         if ( MaxPage == -1 )
  241.             wsprintf (szLine, "Printing page %i . . .", CurrentPage);
  242.         else
  243.             wsprintf (szLine, "Printing page %i of %i", CurrentPage, MaxPage);
  244.  
  245.         SendDlgItemMsg (ID_PAGEOFPAGE, WM_SETTEXT, 0, (LPARAM) szLine);    
  246.     }
  247. }
  248.  
  249. void TPrinterAbortDlg::SetCurrentPage (int p)
  250. {
  251.     char    szLine[80];
  252.  
  253.     CurrentPage = p;
  254.  
  255.     if ( MaxPage )
  256.     {
  257.         if ( MaxPage == -1 )
  258.             wsprintf (szLine, "Printing page %i . . .", CurrentPage);
  259.         else
  260.             wsprintf (szLine, "Printing page %i of %i", CurrentPage, MaxPage);
  261.  
  262.         SendDlgItemMsg (ID_PAGEOFPAGE, WM_SETTEXT, 0, (LPARAM) szLine);
  263.     }
  264. }
  265.  
  266. void TPrinterAbortDlg::WMCommand(RTMessage)
  267. {
  268.     *pfUserAbort = TRUE;
  269. }
  270.  
  271. /*------------------------------------------------------------------------------------------*/
  272. /*    Class TPrinter                                                                            */
  273. /*------------------------------------------------------------------------------------------*/
  274. /*                                                                                          */
  275. /*    Abstract:                                                                               */
  276. /*                                                                                          */
  277. /*    TPrinter represents the physical printer device. To print a TPrintedPage, send the        */
  278. /*    TPrintedPage to the TPrinter's Print function.                                          */
  279. /*                                                                                          */
  280. /*------------------------------------------------------------------------------------------*/
  281.  
  282. TPrinter::TPrinter()
  283. {
  284.     hDevNames = NULL;
  285.     hDevMode  = NULL;
  286.  
  287.     DeviceModule = 0;
  288.     Error = 0;
  289.  
  290.     /*    Determine the version of Windows...
  291.      *
  292.      *  The following code sets fBefore31 to TRUE if the version of Windows that is currently
  293.      *    running is a version prior to Version 3.1. If the current version of Windows is
  294.      *  Version 3.1 or higher, fBefore31 is set to FALSE.
  295.      *
  296.      *    This flag is used throughout the code to impliment version specific code.
  297.      */
  298.  
  299.     if ( LOBYTE(LOWORD(GetVersion())) < 3 )
  300.         fBefore31 = TRUE;
  301.     else
  302.         if ( LOBYTE(LOWORD(GetVersion())) == 3 )
  303.             if ( HIBYTE(LOWORD(GetVersion())) == 0 )
  304.                 fBefore31 = TRUE;
  305.             else
  306.                 fBefore31 = FALSE;
  307.         else
  308.             fBefore31 = FALSE;
  309.  
  310.     SetDevice();              // Associate with default printer
  311. }
  312.  
  313. // Deallocate allocated resources
  314.  
  315. TPrinter::~TPrinter()
  316. {
  317.     ClearDevice();
  318. }
  319.  
  320. // Clears the association of this object with the current device
  321.  
  322. void TPrinter::ClearDevice()
  323. {
  324.     if ( hDevNames != NULL )
  325.     {
  326.         GlobalFree (hDevNames);
  327.         hDevNames = NULL;
  328.     }
  329.  
  330.     if ( hDevMode != NULL )
  331.     {
  332.         GlobalFree (hDevMode);
  333.         hDevMode = NULL ;
  334.     }
  335.  
  336.     if ((int)DeviceModule >= 32)
  337.     {
  338.         FreeLibrary(DeviceModule);
  339.         DeviceModule = 0;
  340.     }
  341.  
  342.     Status = PSTAT_UNASSOCIATED;
  343. }
  344.  
  345.  
  346. /*    Associates the printer object with a new device. If the ADevice parameter is NULL the
  347.  *    Windows default printer is used, otherwise, the parameters must be ones contained in the
  348.  *    [devices] section of the WIN.INI file.
  349.  */
  350.  
  351. void TPrinter::SetDevice()
  352. {
  353.     PRINTDLG    pd ;
  354.  
  355.     if ( hDevNames != NULL )
  356.     {
  357.         GlobalFree (hDevNames);
  358.         hDevNames = NULL;
  359.     }
  360.  
  361.     if ( hDevMode != NULL )
  362.     {
  363.         GlobalFree (hDevMode);
  364.         hDevMode = NULL ;
  365.     }
  366.  
  367.     pd.lStructSize = sizeof(PRINTDLG);
  368.     pd.hDevMode = NULL;
  369.     pd.hDevNames = NULL;
  370.     pd.Flags = PD_RETURNDEFAULT ;
  371.  
  372.     if ( PrintDlg ( &pd ) )
  373.     {
  374.         hDevMode = pd.hDevMode ;
  375.         hDevNames = pd.hDevNames ;
  376.         Status = PSTAT_OK;
  377.     }
  378.     else
  379.         Status = PSTAT_UNASSOCIATED;
  380. }
  381.  
  382. // Configure brings up a dialog as a child of the given window
  383. // to configure the associated printer driver.
  384.  
  385. void TPrinter::Configure(PTWindowsObject Window)
  386. {
  387.     PRINTDLG        pd ;
  388.  
  389.     pd.lStructSize = sizeof(PRINTDLG);
  390.     pd.hwndOwner   = Window->HWindow;
  391.     pd.hDevMode    = hDevMode;
  392.     pd.hDevNames   = hDevNames;
  393.     pd.hDC           = NULL;
  394.     pd.Flags       = PD_PRINTSETUP | PD_SHOWHELP;
  395.     pd.hInstance   = NULL;
  396.  
  397.     if ( PrintDlg (&pd) )
  398.     {
  399.         hDevMode  = pd.hDevMode;
  400.         hDevNames = pd.hDevNames;
  401.         Status    = PSTAT_OK;
  402.     }
  403.     else
  404.         Status = PSTAT_UNASSOCIATED;
  405. }
  406.  
  407. // Returns a device context for the associated printer, 0 if an
  408. // error occurs or Status is != PSTAT_OK
  409.  
  410. HDC TPrinter::GetDC(PTWindowsObject ParentWin, Rint nCopies, Rint nFromPage, Rint nToPage)
  411. {
  412.     PRINTDLG        pd ;
  413.  
  414.     pd.lStructSize = sizeof(PRINTDLG);
  415.     pd.hwndOwner   = ParentWin->HWindow;
  416.     pd.hDevMode    = hDevMode;
  417.     pd.hDevNames   = hDevNames;
  418.     pd.hDC           = NULL;
  419.     pd.nCopies     = nCopies;
  420.     pd.nFromPage   = nFromPage;
  421.     pd.nToPage       = nToPage;
  422.     pd.nMinPage    = 1;
  423.     pd.nMaxPage    = 9999;
  424.     pd.Flags       = PD_RETURNDC | PD_ALLPAGES | PD_SHOWHELP | PD_USEDEVMODECOPIES ;
  425.     pd.hInstance   = NULL;
  426.  
  427.     if ( Status == PSTAT_OK )
  428.     {
  429.         if ( PrintDlg (&pd) )
  430.         {
  431.             hDevMode  = pd.hDevMode;
  432.             hDevNames = pd.hDevNames;
  433.  
  434.             nFromPage = pd.nFromPage;
  435.             nToPage   = pd.nToPage;
  436.             nCopies   = pd.nCopies;
  437.  
  438.             return pd.hDC ;
  439.         }
  440.     }
  441.  
  442.     return 0;
  443. }
  444.  
  445.  
  446. BOOL TPrinter::Print(PTWindowsObject ParentWin, PTPrintedPage Printout)
  447. {
  448.     typedef BOOL (FAR PASCAL *PTYieldProc)( BOOL );
  449.  
  450.     int                    i;
  451.     int                    nCopies;
  452.     int                    nFromPage, nToPage;
  453.     int                    nMaxPage;
  454.     PTYieldProc            YieldProcInst;
  455.     WORD                PageNumber;
  456.     LPSTR                lpName;
  457.     LPSTR                Device;
  458.     LPSTR                Port;
  459.     DEVNAMES FAR *        lpDevNames;
  460.     PTDialogTemplate    ADialogTemplate;
  461.  
  462.     BOOL result = FALSE;        //    Assume error occurred
  463.     fUserAbort = FALSE;            //    Assume the user does not wish to cancel the print
  464.     Error = 0;                    //    Clear Error Flag
  465.  
  466.     /*    Make sure all the required objects exist and that they are properly initialized...
  467.     */
  468.  
  469.     if ( Printout == NULL )
  470.         return result;
  471.  
  472.     if ( ParentWin == NULL )
  473.         return result;
  474.  
  475.     if ( Status != PSTAT_OK )
  476.     {
  477.         Error = SP_ERROR;
  478.         ReportError(ParentWin, Printout);
  479.         return result;
  480.     }
  481.  
  482.     /*    Get a handle to the Device Context for the printer...
  483.     */
  484.  
  485.     nMaxPage = Printout->GetMaxPage();
  486.  
  487.     nCopies = 1;
  488.     nFromPage = 1 ;
  489.     nToPage = ( nMaxPage < 1 ) ? 9999 : nMaxPage ;
  490.     PrnDC = GetDC(ParentWin, nCopies, nFromPage, nToPage);
  491.  
  492.     if ( PrnDC == 0 )
  493.         return result;
  494.  
  495.     /*    Display the "Printing" dialog box...
  496.     */
  497.  
  498.     lpDevNames = (DEVNAMES FAR *) GlobalLock(hDevNames);
  499.     lpName = (Pchar) lpDevNames ;
  500.     Device = (lpName + lpDevNames->wDeviceOffset);
  501.     Port   = (lpName + lpDevNames->wOutputOffset);
  502.  
  503.     ADialogTemplate = new TDialogTemplate ( DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
  504.                                             84, 46, 142, 92, "BorDlg", "Print");
  505.  
  506.     ADialogTemplate->AddControl ( SS_CENTER | WS_VISIBLE | WS_CHILD | WS_GROUP, -1,  9,  9, 124, 8, DTCS_STATIC, "Printing");
  507.     ADialogTemplate->AddControl ( SS_CENTER | WS_VISIBLE | WS_CHILD | WS_GROUP, 101, 9, 17, 124, 8, DTCS_STATIC, "%s");
  508.     ADialogTemplate->AddControl ( SS_CENTER | WS_VISIBLE | WS_CHILD | WS_GROUP, 102, 9, 25, 124, 8, DTCS_STATIC, "on the %s Printer");
  509.     ADialogTemplate->AddControl ( SS_CENTER | WS_VISIBLE | WS_CHILD | WS_GROUP, 103, 9, 33, 124, 8, DTCS_STATIC, "connected to %s");
  510.     ADialogTemplate->AddControl ( SS_CENTER | WS_VISIBLE | WS_CHILD | WS_GROUP, 104, 9, 49, 124, 8, DTCS_STATIC, "Printing page %i on %i");
  511.     ADialogTemplate->AddControl ( WBS_DEFPUSHBUTTON | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP,
  512.                                     IDCANCEL, 55, 69, 33, 15, "WICSButton", NULL);
  513.     ADialogTemplate->AddControl ( 1 | WS_CHILD | WS_VISIBLE, -1, 6, 6, 130, 56, "BorShade", NULL);
  514.                                      
  515.     PTPrinterAbortDlg Dlg = (PTPrinterAbortDlg) GetApplicationObject()->MakeWindow(
  516.                 new TPrinterAbortDlg(ParentWin, ADialogTemplate, Printout->GetTitle(), Device, Port, fUserAbort) );
  517.  
  518.     Dlg->SetMaxPage ( nMaxPage );
  519.     Dlg->SetCurrentPage (nFromPage);
  520.     
  521.     GlobalUnlock (hDevNames);
  522.  
  523.     if ( Dlg == NULL )
  524.     {
  525.         DeleteDC(PrnDC);
  526.         return result;
  527.     }
  528.  
  529.     /*    Disable the parent window, create the Yield Procedure and call it to enable screen
  530.      *    Painting.
  531.      */
  532.  
  533.     EnableWindow(ParentWin->HWindow, FALSE);
  534.  
  535.     YieldProcInst = (PTYieldProc) MakeProcInstance( (FARPROC) YieldProc, GetApplicationObject()->hInstance);
  536.  
  537.     if ( !(*YieldProcInst)(fUserAbort) )
  538.         Error = SP_APPABORT;
  539.  
  540.     // Get the page size
  541.  
  542.     PageSize.x = GetDeviceCaps(PrnDC, HORZRES);
  543.     PageSize.y = GetDeviceCaps(PrnDC, VERTRES);
  544.  
  545.     dpi.x = GetDeviceCaps(PrnDC, LOGPIXELSX);
  546.     dpi.y = GetDeviceCaps(PrnDC, LOGPIXELSY); 
  547.  
  548.     if ( !(*YieldProcInst)(fUserAbort) )
  549.         Error = SP_APPABORT;
  550.  
  551.     for ( i = 0 ; i < nCopies && !Error ; i++ )
  552.     {
  553.         Flags = PFUNC_BOTH;
  554.         PageNumber = nFromPage;
  555.  
  556.         if ( fBefore31 )
  557.         {
  558.             if ((Error = Escape(PrnDC, STARTDOC, strlen(Printout->GetTitle()), Printout->GetTitle(), NULL)) == 0 )
  559.             {
  560.                 BOOL    fMorePages = TRUE;
  561.  
  562.                 while ( fMorePages && !Error )
  563.                 {
  564.                     Dlg->SetCurrentPage (PageNumber);
  565.  
  566.                     (*YieldProcInst)(fUserAbort);
  567.  
  568.                     if ( fUserAbort )
  569.                         Error = SP_APPABORT;
  570.                     else
  571.                     {
  572.                         Printout->PrintPage(PrnDC, PageNumber, PageSize, dpi);
  573.  
  574.                         if ((Error = Escape(PrnDC, NEWFRAME, 0, NULL, NULL)) == 0 )
  575.                         {
  576.                             PageNumber++;
  577.                             fMorePages = Printout->IsNextPage();
  578.                         }
  579.                     }
  580.  
  581.                     if ( PageNumber > nToPage )
  582.                            fMorePages = FALSE;
  583.                 }
  584.  
  585.                 if ( Error )
  586.                     Escape(PrnDC, ABORTDOC, 0, NULL, NULL);
  587.                 else
  588.                     Escape(PrnDC, ENDDOC, 0, NULL, NULL);
  589.             }
  590.         }
  591.         else
  592.         {
  593.             DOCINFO    DocInfo;
  594.             BOOL    fMorePages = TRUE ;
  595.  
  596.             DocInfo.cbSize = sizeof(DOCINFO);
  597.             DocInfo.lpszDocName = Printout->GetTitle();
  598.                DocInfo.lpszOutput = NULL;
  599.  
  600.             Error = ( StartDoc (PrnDC, &DocInfo) > 0 ) ? 0 : SP_ERROR ;
  601.  
  602.             while ( fMorePages && !Error )
  603.             {
  604.                 Dlg->SetCurrentPage (PageNumber);
  605.  
  606.                 Error = ( StartPage (PrnDC) > 0 ) ? 0 : SP_ERROR ;
  607.  
  608.                 if ( !Error )
  609.                 {
  610.                     Printout->PrintPage(PrnDC, PageNumber, PageSize, dpi);
  611.  
  612.                     Error = EndPage (PrnDC);
  613.  
  614.                     if ( Error > 0 )
  615.                         Error = 0 ;
  616.  
  617.                     if ( !Error )
  618.                     {
  619.                         /*    Call the Abort Proc between pages
  620.                          */
  621.  
  622.                         (*YieldProcInst)(fUserAbort);
  623.  
  624.                         if ( fUserAbort )
  625.                             Error = SP_APPABORT;
  626.  
  627.                         PageNumber++;
  628.                         fMorePages = Printout->IsNextPage();
  629.  
  630.                     }
  631.                 }
  632.  
  633.                 if ( PageNumber > nToPage )
  634.                        fMorePages = FALSE;
  635.             }
  636.  
  637.             if ( Error )
  638.                 AbortDoc (PrnDC);
  639.             else
  640.                    Error = EndDoc (PrnDC);
  641.         }
  642.     }
  643.  
  644.     // Free allocated resources
  645.  
  646.     FreeProcInstance((FARPROC) YieldProcInst);
  647.     EnableWindow(ParentWin->HWindow, TRUE);
  648.     delete Dlg;
  649.     DeleteDC(PrnDC);
  650.  
  651.     if ( Error & SP_NOTREPORTED )
  652.         ReportError(ParentWin, Printout);
  653.  
  654.     result = (Error > 0) && (!fUserAbort);
  655.  
  656.     fUserAbort = FALSE;
  657.  
  658.     return result;
  659. }
  660.  
  661. void TPrinter::ReportError(PTWindowsObject ParentWin, PTPrintedPage Printout)
  662. {
  663.     PTDialogTemplate    ADialogTemplate;
  664.     Pchar                 Title;
  665.     Pchar                 ErrorCaption;
  666.     Pchar                 ErrorMsg;
  667.     Pchar                 ErrorTemplate = "'%s' was not printed. Reason: %s.";
  668.     Pchar                ErrorText = new char [128];
  669.  
  670.     switch (Error)
  671.     {
  672.         case SP_APPABORT:
  673.             ErrorMsg = "Printing canceled";
  674.             break;
  675.  
  676.         case SP_ERROR:
  677.             ErrorMsg = "Error encountered during print";
  678.             break;
  679.  
  680.         case SP_OUTOFDISK:
  681.             ErrorMsg = "Out of disk space";
  682.             break;
  683.  
  684.         case SP_OUTOFMEMORY:
  685.             ErrorMsg = "Out of memory";
  686.             break;
  687.  
  688.         case SP_USERABORT:
  689.             ErrorMsg = "Printing aborted in Print Manager";
  690.             break;
  691.  
  692.         default:
  693.             ErrorMsg = "Unknown error";
  694.             break;
  695.     }
  696.  
  697.     Title = Printout->GetTitle();
  698.     ErrorCaption = "Print Error";
  699.  
  700.     wsprintf(ErrorText, ErrorTemplate, Title, ErrorMsg);
  701.  
  702.     ADialogTemplate = new TDialogTemplate ( DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
  703.                                             18, 18, 217, 92, "BorDlg", Title);
  704.  
  705.     ADialogTemplate->AddControl ( SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 100, 35, 15, 170,  8, DTCS_STATIC, ErrorCaption);
  706.     ADialogTemplate->AddControl ( SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 101, 12, 32, 193, 29, DTCS_STATIC, ErrorText);
  707.     ADialogTemplate->AddControl ( SS_ICON | WS_CHILD | WS_VISIBLE | WS_GROUP, 102, 12, 11,  16, 16, DTCS_STATIC, "");
  708.     ADialogTemplate->AddControl ( WBS_DEFPUSHBUTTON | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP,
  709.                                     IDOK, 92, 72, 33, 15, "WICSButton", NULL);
  710.     ADialogTemplate->AddControl ( 1 | WS_CHILD | WS_VISIBLE, -1, 7, 7, 203, 58, "BorShade", NULL);
  711.                                      
  712.     GetApplicationObject()->ExecDialog( new TPrinterErrorDlg(ParentWin, ADialogTemplate) );
  713.  
  714.     delete ErrorText;
  715. }
  716.